Software transactional memory (STM) is a concurrency control mechanism analogous to database transactions for controlling access to shared memory in concurrent computing. A transaction in the context of transactional memory is a piece of code that executes a series of reads and writes to shared memory. STM is used as an alternative to traditional locking mechanisms. Programmers put a declarative annotation (e.g. atomic) around a code block to indicate safety properties they require and the system automatically guarantees that this block executes atomically with respect to other protected code regions. The software transactional memory programming model prevents lock-based priority-inversion and deadlock problems.
While typical STM systems have many advantages, they still require the programmer to be careful in avoiding unintended memory access orderings. For example, the order in which transactions are committed (i.e. commit processing) in a typical STM environment is unconstrained. Transactions race with one another to commit, meaning that whether transaction 1 commits before transaction 2 or after is often a product of the dynamic scheduling of the program (and often by program-specific logic too). Moreover, if two transactions conflict, such as by trying to write to the same piece of memory, then their committing order can be arbitrarily decided based on one of many possible contention management policies. In both of these scenarios, no particular commit order is guaranteed; therefore the burden is on the programmer to make sure that his/her program works correctly with either order. This makes parallel programming very difficult.
One scenario in which order of execution may be important, and where parallelism may be very attractive, is when executing multiple iterations of a loop in parallel. Take a classic for . . . each loop, as shown below:
ForEach (string s in List<string>){ S;}
During each iteration of the loop, the statement S in the body of the loop will be executed. Such a loop was written to execute sequentially, with the first iteration of the loop finishing before the second one begins, and so on. If such a sequential loop is executed in parallel, without extra precautions to deal with possible side effects or order dependency, unexpected results could occur.